Presentación Final: Propuesta de Soluciones para Salud Digna

Authors

Miguel Ángel Pérez Granados

Juan Manuel Hernández Solano

Leonardo Cumplido Mendoza

Francisco Javier Chávez Ochoa

Published

June 4, 2025

Caso 1

Planteamiento del problema y panorama general

Miles de pacientes acuden diariamente a Salud Digna para tomar estudios médicos, pero deben tomar un turno antes de ser atendidos. En la fila de espera se le da una mayor prioridad a usuarios que sean mujeres embarazadas o adultos mayores frente al resto de usuarios.

El desafío principal es optimizar el tiempo de espera de los usuarios para que este no rebase los 20 minutos independientemente de la prioridad de su turno.

Existen 4 tipos de prioridad en usuarios:

  • P representa un turno prioritario.
  • C representa un turno con cita.
  • F representa un turno con folio pagado.
  • N representa un turno no prioritario.

Propuesta de Solución

Se propone un algoritmo para gestionar una fila de espera de usuarios utilizando una estructura inicial de tipo FIFO (First In, First Out), sin importar la prioridad del turno. Posteriormente, se permite que los usuarios con prioridad P (Prioritaria) puedan adelantar su posición en la fila bajo ciertas reglas y restricciones.

Variables del sistema

Se definen cuatro variables clave que regulan el comportamiento de la fila:

  • THRESHOLD: Tiempo máximo ideal (en minutos) que debe esperar un usuario con prioridad diferente a P.
  • P_THRESHOLD: Tiempo máximo ideal (en minutos) que debe esperar un usuario con prioridad P.
  • MAX_JUMPS_P: Número máximo de saltos permitidos en la fila para un usuario con prioridad P.
  • JUMPS_LIMIT: Número máximo de veces que un usuario con prioridad distinta a P puede ser rebasado en la fila.

Reglas para los saltos de usuarios P

  1. Si el tiempo de espera estimado de un usuario con prioridad P es mayor que P_THRESHOLD, entonces se evalúa la posibilidad de adelantar su lugar en la fila.
  2. El usuario P analiza a los usuarios que se encuentran delante de él:
    • Si el siguiente usuario también tiene prioridad P, entonces no se permite el salto.
  3. Por cada usuario que podría ser rebasado:
    • Si ese usuario ya ha sido rebasado JUMPS_LIMIT veces, el usuario P no puede adelantarlo.
    • Se estima el nuevo tiempo total en la fila para el usuario que sería rebasado. Si este nuevo tiempo excede THRESHOLD, entonces se evalúa lo siguiente:
      • Si el usuario P ha realizado menos de MAX_JUMPS_P saltos, se le permite continuar adelantando.
  4. Una vez que el usuario P haya adelantado suficiente y su tiempo estimado de espera sea menor a P_THRESHOLD, se detienen los saltos.

Este algoritmo permite equilibrar la atención prioritaria sin afectar excesivamente a los demás usuarios en la fila.

Comparación de Resultados

Conclusión sobre el impacto del algoritmo

Sucursal Antes (min) Después (min) Δ Abs (min) Δ Rel (%)
Culiacán 2.04 0.66 −1.38 −67.7 %
Culiacán Cañadas 2.63 1.96 −0.67 −25.5 %
Culiacán Colegio Militar 6.26 2.68 −3.59 −57.3 %
Culiacán La Conquista 4.16 6.26 +2.10 +50.5 %

Supuestos Actuales

  • Operación Estática de Módulos de Atención: El modelo actual asume que todos los módulos de atención (ventanillas) se encuentran operativos de forma continua durante el horario de servicio.
  • Atención Garantizada (Sin Abandono Previo): Se considera que todos los pacientes son atendidos, siempre y cuando lleguen antes del cierre de la sucursal, y haya ventanillas disponibles antes del cierre, sin contemplar la posibilidad de abandono previo a la atención.

Sugerencias para Futuras Iteraciones del Modelo

  • Simulación Dinámica de Módulos: Implementar la capacidad de simular la apertura y cierre variable de los módulos de atención, reflejando patrones operativos reales.
  • Incorporación de Tasa de Abandono: Introducir un componente de ruido estocástico para modelar el porcentaje de pacientes que podrían retirarse de la sucursal antes de recibir atención. Impacto Esperado

La implementación de estas sugerencias permitirá desarrollar un modelo con mayor fidelidad a las condiciones operativas reales.

Entregable (Implementación)

La implementación de este algoritmo sigue los principios de Clean Architecture, lo que permite una separación clara entre la lógica de negocio, la lógica de aplicación y las interfaces. Esta estructura facilita el mantenimiento, la escalabilidad y las pruebas del sistema.

El código fuente y su documentación completa se encuentran disponibles en el siguiente enlace:

Repositorio

Caso 2

Planteamiento del problema y panorama general

Salud Digna enfrenta el desafío de gestionar eficientemente el flujo de pacientes que requieren múltiples estudios (modalidades) en sus clínicas, con el objetivo de minimizar los tiempos de espera y mejorar la experiencia del paciente.

Existen 11 tipos de estudios:

  • Densitometria
  • Electrocardiograma
  • Laboratorio
  • Mastografia
  • Nutrición
  • Optometria
  • Papanicolaou
  • Rayos X
  • Resonancia Magnética
  • Tomografía
  • Ultrasonido

Esta sección detalla una solución propuesta que combina la preparación de datos históricos, la simulación de escenarios y la evaluación de diversos algoritmos de enrutamiento.

Se analizaron datos de tiempos de atención y espera, así como la capacidad de los consultorios, para alimentar un modelo de simulación. Los algoritmos evaluados varían en complejidad y enfoque, desde estrategias “greedy” simples hasta búsquedas exhaustivas.

Se incluye un análisis de costos preliminar considerando la complejidad algorítmica y el posible despliegue en servicios de Azure.

El desafío principal es determinar la secuencia más eficiente para que cada paciente complete sus estudios médicos requeridos dentro de la clínica, minimizando su tiempo total de su visita.

Preparación de Datos (RetoColas2_preparacion.ipynb)

Para alimentar el sistema de simulación y los algoritmos, se realizó un proceso de preparación de datos utilizando información histórica contenida en DataTiempos.csv (tiempos de pacientes) y Consultorios.csv (número de consultorios). Los pasos clave incluyeron:

  • Carga y Limpieza Inicial:
    • Conversión de las columnas TEPMinutos (Tiempo Esperado Promedio en Minutos) y TAPMinutos (Tiempo de Atención Promedio en Minutos) a formato numérico.
    • Cálculo de TotalMinutos como la suma de TEPMinutos y TAPMinutos.
    • Manejo de datos faltantes mediante la eliminación de filas (dropna) que no contuvieran valores válidos en TotalMinutos, Sucursal o EstudioModalidad.
  • Eliminación de Outliers:
    • Se aplicó un método basado en Z-score para identificar y eliminar outliers. Se utilizó un umbral de 3 desviaciones estándar.
    • Este proceso se realizó para TAPMinutos y TEPMinutos, agrupando por Sucursal y EstudioModalidad para considerar las variaciones inherentes a cada contexto.
  • Análisis Exploratorio:
    • Se desarrollaron funciones para visualizar el tiempo medio de espera por estudio en una sucursal (graficar_tiempo_medio_por_estudio) y los horarios pico de atención por estudio y periodo del día (graficar_horarios_pico_estudios). Estas visualizaciones ayudan a comprender los patrones de demanda y operación.
  • Extracción de Métricas Relevantes para la Simulación:
    • average_tap_dict: Un diccionario con el tiempo promedio de atención (TAPMinutos) para cada combinación de (Sucursal, EstudioModalidad).
    • consultorios_grouped_dict: Un diccionario que mapea (Sucursal, EstudioModalidad) al número máximo de consultorios disponibles.
    • processing_rate_dict: Calculado como average_tap_dict[key] / consultorios_grouped_dict[key], representa la tasa de procesamiento promedio por consultorio para cada servicio.
    • average_tep_dict (nombrado formatted_average_tep_dict en el notebook): Contiene el tiempo promedio de espera (TEPTimeDelta, calculado como TEPHoraFin - TEPHoraInicio) agrupado por (Sucursal, EstudioModalidad, IntervalStartTime), donde IntervalStartTime representa intervalos de 30 minutos a lo largo del día.
    • counts_by_time_slot (nombrado formatted_total_counts_dict en el notebook): Un diccionario con el conteo total de estudios realizados, agrupados por (Sucursal, EstudioModalidad, TimeOfDaySlot), donde TimeOfDaySlot también representa intervalos de 30 minutos.
  • División de Datos: El conjunto de datos preprocesado (df_sorted) se dividió en conjuntos de entrenamiento (80%) y prueba (20%) basados en FechaEvento. El conjunto de prueba se guardó en DataTiempos_prueba.csv para ser utilizado en la simulación.

Datos de Entrada del Sistema

El sistema propuesto utiliza una variedad de datos para informar sus decisiones y actualizar sus parámetros:

  • Hora de llegada a consultorios de cada paciente visitante.
  • Modalidades que visita cada paciente visitante.
  • Pacientes esperados por clínica, modalidad, día y hora.
  • Hora de entrada al consultorio de cada paciente atendido.
  • Hora de salida del consultorio de cada paciente atendido.
  • Tiempo promedio de atención por clínica, modalidad y hora del día de la semana.
  • Número de consultorios por modalidad de la clínica.

Para mantener los parámetros actualizados, se utiliza una ventana de tiempo del último mes anterior. El algoritmo se ejecuta considerando la hora y día de la semana para ajustar sus decisiones a los patrones observados.

Configuración de la Simulación (RetoColas2_simulacion.ipynb)

Se desarrolló un script de simulación para evaluar el desempeño de diferentes algoritmos de enrutamiento.

  • Entorno de Simulación:
    • La simulación opera sobre una sucursal específica (e.g., SIMULATED_SUCURSAL = 'COYOACAN').
    • Genera un número configurable de pacientes (NUM_SIMULATED_PATIENTS) con horarios de llegada distribuidos aleatoriamente dentro de un rango horario definido (SIMULATION_START_HOUR, SIMULATION_END_HOUR).
    • A cada paciente simulado se le asigna un conjunto de estudios requeridos (máximo MAX_STUDIES_PER_PATIENT), cuya selección se basa en las frecuencias observadas en los datos históricos (counts_by_time_slot para frecuencias específicas del intervalo de llegada, con fallback a frecuencias generales de la sucursal).
  • Lógica Central de la Simulación (run_multi_room_simulation_flexible):
    • Maneja una cola de eventos para gestionar llegadas de pacientes y finalizaciones de estudios.
    • Mantiene una clinic_waiting_line para pacientes que han llegado y esperan asignación o disponibilidad de sala.
    • Rastrea la ocupación de las salas (room_occupancy) para determinar cuándo un consultorio para un estudio específico (EstudioModalidad actúa como la “sala”) estará disponible.
    • Utiliza estimate_current_study_queues_wait_times para estimar el tiempo de espera para un estudio, considerando la disponibilidad de la sala y el número de otros pacientes en la clinic_waiting_line que también requieren ese estudio y están disponibles antes o al mismo tiempo que el paciente actual. Este cálculo se apoya en el processing_rate_dict.
    • Emplea get_tep_historical_estimate para obtener el tiempo de espera promedio histórico (TEP) para un estudio en un intervalo de tiempo específico, usando el average_tep_dict (que contiene TEPTimeDelta por slot).

Algoritmos de Enrutamiento Evaluados

Se implementaron y evaluaron los siguientes algoritmos:

  1. Greedy Simple (Siguiente Paso): Asigna al paciente al próximo estudio disponible que tenga el menor tiempo de espera estimado en cola actualmente. No planifica una ruta completa.

  2. Greedy de Fila (Siguiente Paso): Asigna al paciente al próximo estudio disponible que tenga la cola más corta en cantidad de pacientes actualmente. No planifica una ruta completa.

  3. Greedy Valor Esperado (Siguiente Paso): Similar al Greedy Simple, pero la métrica de decisión es tiempo_espera_estimado_actual - TEP_histórico_del_intervalo_actual. Intenta priorizar estudios cuya espera actual sea favorable comparada con su histórico.

  4. Aleatorio (Ruta Completa): Al llegar el paciente, se genera una permutación aleatoria de todos los estudios que requiere, y esa ruta se sigue secuencialmente.

  5. Búsqueda Exhaustiva Simple (Siguiente Paso o Ruta Completa):

    • Siguiente Paso: Evalúa todas las permutaciones de los estudios restantes del paciente. Para cada permutación, calcula un tiempo total esperado: el primer estudio de la permutación usa la espera de cola actual + TAP; los estudios subsiguientes usan el TEP histórico del slot futuro (cuando se estima que comenzaría ese estudio) + TAP. Elige el primer estudio de la permutación con el menor tiempo total esperado.
    • Ruta Completa: Similar al anterior, pero elige y asigna la secuencia completa de estudios de la permutación con el menor tiempo total esperado.
  6. Búsqueda Exhaustiva Valor Esperado (Siguiente Paso o Ruta Completa):

    • Siguiente Paso: Similar a la Búsqueda Exhaustiva Simple, pero la métrica para los estudios subsiguientes en una permutación es: (TEP_slot_futuro - (tiempo_cola_actual_decision - TEP_histórico_slot_actual_decision)) + TAP. Intenta cuantificar la “ganancia” o “pérdida” de tomar un estudio ahora versus su espera histórica, proyectado a futuro. Elige el primer estudio de la permutación con la menor métrica acumulada.
    • Ruta Completa: Asigna la secuencia completa de la permutación con la menor métrica acumulada.

Análisis de Costos

Complejidad Algorítmica

  • Greedy (Simple y Valor Esperado): Son relativamente eficientes. Para cada decisión de siguiente estudio (M estudios posibles), se realiza un cálculo. La complejidad por decisión es O(M). Si se deben ordenar las opciones, podría ser O(M log M).
  • Aleatorio (Ruta Completa): La generación de la ruta inicial es O(S) donde S es el número de estudios solicitados. Las decisiones subsecuentes son O(1).
  • Búsqueda Exhaustiva (Siguiente Paso y Ruta Completa): Estos son los más costosos computacionalmente. Evaluar todas las permutaciones de S estudios restantes implica S! permutaciones. Para cada permutación, se calculan los tiempos para S estudios. La complejidad aproximada es O(S! * S). Esto se vuelve intratable rápidamente a medida que S aumenta (e.g., para 8 estudios, 8! = 40,320 permutaciones).
    • La versión “Siguiente Paso” realiza esta búsqueda exhaustiva en cada punto de decisión.
    • La versión “Ruta Completa” la realiza una vez al inicio (o cuando la ruta precalculada se interrumpe).

Estimación de Costo de Hosting en Azure

El costo de desplegar esta solución en Azure dependerá de los componentes elegidos y la carga esperada.

  1. Almacenamiento de Datos:
    • Los archivos CSV (DataTiempos.csv, Consultorios.csv) y los diccionarios serializados (.pkl) pueden almacenarse en Azure Blob Storage. El costo es bajo, basado en la cantidad de datos almacenados y las transacciones. Para los tamaños de datos manejados, sería insignificante.
    • Si los datos crecen significativamente o se requiere una base de datos relacional, Azure SQL Database o Azure Database for PostgreSQL/MySQL serían opciones, con costos variables según el nivel de rendimiento (DTUs/vCores) y almacenamiento.
  2. Procesamiento de Datos (Preparación):
    • La ejecución del notebook RetoColas2_preparacion.ipynb para la limpieza, análisis y extracción de métricas puede realizarse en:
      • Azure Machine Learning Workspace (Compute Instances): Permite ejecutar Jupyter Notebooks. El costo depende del tamaño de la VM y el tiempo de ejecución. Para ejecuciones periódicas (ej. mensual), se puede iniciar y detener la instancia para controlar costos.
      • Azure Databricks: Para cargas de trabajo de Spark más grandes, aunque para este caso podría ser excesivo a menos que el volumen de datos crezca exponencialmente.
    • Azure Data Factory: Podría usarse para orquestar la ingesta y preparación de datos de forma programada si el proceso se automatiza.

Azure Functions (Serverless) – (Supuesto) 1,000 iteraciones diarias Supuestos actualizados: * Cada 1,000 iteraciones = 1 ejecución de Azure Function * Tiempo por ejecución: 2 segundos * Memoria usada: 512 MB (0.5 GB) * Total ejecuciones diarias: 1,000 * Precios: * Costo por ejecución: $ 0.0000002 USD * Costo por GB-segundo: $ 0.000016 USD * Capa gratuita: 1 millón de ejecuciones y 400,000 GB-segundos por mes

Cálculo diario (sin capa gratuita): * GB-segundos por ejecución: 0.5 GB × 2 s = 1 GB-segundo * Total GB-segundos por día: 1,000 × 1 = 1,000 GB-segundos * Costo por ejecuciones: 1,000 × $0.0000002 = $0.0002 USD * Costo por GB-segundos: 1,000 × $0.000016 = $0.016 USD * Costo total diario: $0.0002 + $0.016 = $0.0162 USD

Cálculo mensual (30 días, sin capa gratuita): * $0.0162 × 30 días = $0.486 USD/mes

Resultados de la Simulación

Las simulaciones se ejecutaron para varias sucursales, generando pacientes y sus solicitudes de estudio. El principal indicador de rendimiento comparado fue el “Tiempo Promedio en Clínica” (avg_time_in_clinic). A continuación, se presentan los resultados promedio entre las sucursales simuladas:

Algoritmo Tiempo Promedio en Clínica (minutos)
greedy_linea 119.17
greedy 122.63
exhaustive_E(x) 122.76
greedy_E(x) 123.21
exhaustive 123.04
exhaustive_E(x)_full 123.11
exhaustive_full 123.31
random 124.65

Nota: Estos resultados son un promedio de las simulaciones realizadas en el notebook RetoColas2_simulacion.ipynb.

La simulación sugiere que los algoritmos de búsqueda greedy ofrecen el mayor potencial de reducir el tiempo promedio que un paciente pasa en la clínica, ademas de su baja carga computacional este tiene el beneficio de maximizar la utilización de los consultorios. El algoritmo aleatorio, como es de esperar, presenta el rendimiento menos óptimo.

Aleatorio

Greedy Line

Propuesta

Proponemos utilizar un sistema de turno inteligente en el cual los pacientes reciben una tarjeta que es escaneada al entrar y terminar su consulta, el conectado por whatsapp a los pacientes.

De manera que los pacientes reciban un mensaje cada que salgan de una consulta indicandoles que estudio seguirá, junto con un estimado de tiempo utilizando la informacion en el sistema. Ya que les toque pasar al estudio recibirán un mensaje por whatsapp pero también habrá una pantalla con voceo afuera del consultorio para agilizar el proceso.

Implementación Inicial: Comenzar con el algoritmo Greedy de Línea para el sistema en producción. Es computacionalmente ligeros, adecuado para decisiones en tiempo real (posiblemente desplegados en Azure Functions), y ofrecen una mejora significativa sobre una asignación no optimizada.

Evaluación de Búsqueda Exhaustiva: Para pacientes con un número muy pequeño de estudios restantes (ej. <=3), la Búsqueda Exhaustiva Informada podría ser viable en tiempo real, ya que la dinámica de tiempo cambia.

Entregable (Implementación)

La implementación de este algoritmo sigue los principios de Clean Architecture, lo que permite una separación clara entre la lógica de negocio, la lógica de aplicación y las interfaces. Esta estructura facilita el mantenimiento, la escalabilidad y las pruebas del sistema.

El código fuente y su documentación completa se encuentran disponibles en el siguiente enlace:

Repositorio